#include"StringPool.h"
#include"variable.h"
#include<iostream>
#include<cstring>
#include<time.h> 
#include"FeatureVector.h"
using namespace std;
using namespace boost;

FeatureVector::FeatureVector():vector<Feature>(){
	previous1 = NULL;
	previous2 = NULL;
	negativeSecond = false;
}

FeatureVector::FeatureVector(FeatureVector *fv1, FeatureVector *fv2, bool negSecond):vector<Feature>(){
	previous1 = fv1;
	previous2 = fv2;
	negativeSecond = negSecond;
}

void FeatureVector::construct(int *keys, int size){
	/*
	for(int i = 0; i < size; i++){
		push_back(Feature(keys[i], 1.0));
	}
	*/
	resize(size);
	for(int i = 0; i < size; i++){
		(*this)[i] = Feature(keys[i], 1.0);
	}
	previous1 = NULL;
	previous2 = NULL;
	negativeSecond = false;
}

void FeatureVector::add(int index, double value){
	push_back(Feature(index, value));
}


int* FeatureVector::keys(){
	int len = (int)(size());
	int* keys = new int[len];
	for(int i = 0; i < len; i++){
		keys[i] = (*this)[i].index;
	}
	return keys;
}


void FeatureVector::cat(FeatureVector *f1, FeatureVector *f2){
	previous1 = f1;
	previous2 = f2;
}

void FeatureVector::extend(FeatureVector *f12){
	if(f12->previous1 != NULL){
		extend(f12->previous1);
	}
	if(f12->previous2 != NULL){
		extend(f12->previous2);
	}
	int len = (int)(f12->size());
	for(int i = 0; i < len; i++){
		push_back((*f12)[i]);
	}
}

FeatureVector* FeatureVector::getDistVector(FeatureVector* f12){
	return new FeatureVector(this, f12, true);
}

double FeatureVector::getScore(double* parameters){
	double score = 0.0;

	if(previous1 != NULL){
		score += previous1->getScore(parameters);
	}

	if(previous2 != NULL){
		if(negativeSecond){
			score -= previous2->getScore(parameters);
		}
		else{
			score += previous2->getScore(parameters);
		}
	}

	int len = (int)(size());
	for(int i = 0;i < len; ++i){
		Feature f = (*this)[i];
		score += parameters[f.index] * f.value;
	}
	return score;
}


void FeatureVector::update(double* parameters, double* total, double alpha_k, double upd){

	FeatureVector* f1 = this->previous1;
	FeatureVector* f2 = this->previous2;

	int len = (int)(f1->size());
	for(int i = 0; i < len; ++i){
		Feature f = (*f1)[i];
		parameters[f.index] += alpha_k * f.value;
		total[f.index] += upd * alpha_k * f.value;
	}

	len = (int)(f2->size());

	for(int i = 0; i < len; ++i){
		Feature f = (*f2)[i];
		parameters[f.index] -= alpha_k * f.value;
		total[f.index] -= upd * alpha_k * f.value;
	}
}

bool compare(Feature &f1, Feature &f2){
	return f1.index < f2.index;
}

double FeatureVector::dotProduct(FeatureVector &f12){
	int size = (int)(this->previous1->size()) + (int)(this->previous2->size());
	Hash_Map map1(size);

	vector<int> keys(size);

	size = (int)(f12.previous1->size()) + (int)(f12.previous2->size());
	Hash_Map map2(size);

	int num = 0;
	num = (this->previous1->addFeaturesToMap(map1, false, keys, 0));
	num += (this->previous2->addFeaturesToMap(map1, true, keys, num));

	f12.previous1->addFeaturesToMap(map2, false);
	f12.previous2->addFeaturesToMap(map2, true);

	double result = 0.0;

	for(int i = 0; i < num; i++){
		result += map1.get(keys[i]) * map2.get(keys[i]);
	}
	return result;
}

void FeatureVector::addFeaturesToMap(Hash_Map &map, bool negative){
	int len = (int)(size());
	for(int i = 0; i < len; ++i){
		Feature f;
		if(negative){
			f = (*this)[i].negation();
		}
		else{
			f = (*this)[i];
		}
		map.put(f.index, f.value);
	}
}

int FeatureVector::addFeaturesToMap(Hash_Map &map, bool negative, std::vector<int> &keys, int start){
	int end = start;
	int len = (int)(size());
	for(int i = 0; i < len; ++i){
		Feature f;
		if(negative){
			f = (*this)[i].negation();
		}
		else{
			f = (*this)[i];
		}

		if(!(map.put(f.index, f.value))){
			keys[end++] = f.index;
		}
	}
	return end - start;
}

void FeatureVector::toString(std::string *str){

	vector<Feature>::iterator iter;
	for(iter = begin(); iter != end(); ++iter){
		Feature f = *iter;
		string* s = f.toString();
		//string* ns = new string(*str + *s + ' ');
		//delete(str);
		//str = ns;
		str->append(*s + ' ');
		delete(s);
	}
}

string* FeatureVector::toString(){
	string* str = new string();
	toString(str);
	return str;
}

FeatureVector::~FeatureVector(){
	previous1 = NULL;
	previous2 = NULL;
}

Hash_Map::Hash_Map(int size){
	this->size = size;
	table = new Term[size][3];
	lengths = new int[size];
	memset(lengths, 0, sizeof(int) * size);
	bucket_size = 3;
}

bool Hash_Map::put(int key, double value){
	int hash = key % size;
	while(lengths[hash] != 0){
		for(int i = 0; i < lengths[hash]; i++){
			if(table[hash][i].index == key){
				table[hash][i].value += value;
				return true;
			}
		}
		if(lengths[hash] == bucket_size){
			hash = (hash + 1) % size;
		}
		else{
			table[hash][lengths[hash]].index = key;
			table[hash][lengths[hash]].value = value;
			lengths[hash]++;
			return false;
		}
	}
	table[hash][0].index = key;
	table[hash][0].value = value;
	lengths[hash] = 1;
	return false;
}

double Hash_Map::get(int key){
	int hash = key % size;
	int souce = hash;
	while(lengths[hash] != 0){
		for(int i = 0; i < lengths[hash]; i++){
			if(table[hash][i].index == key){
				return table[hash][i].value;
			}
		}
		if(lengths[hash] != bucket_size){
			return 0.0;
		}
		else{
			hash = (hash +1) % size;
			if(hash == souce){
				break;
			}
		}
	}
	return 0.0;
}

Hash_Map::~Hash_Map(){
	delete[](table);
	delete[](lengths);
}


